#ifndef B2D_SHADERPROGRAM_H
#define B2D_SHADERPROGRAM_H

#include "IShaderProgram.h"

NS_B2D_BEGIN

////////////////////////////////////////////////////////////////////////////////////////////////////
/// \brief	Generic shader base class.
////////////////////////////////////////////////////////////////////////////////////////////////////
class B2D_API Shader
	: public IShader
{
protected:
	/// Type of shader
	const ShaderType mType;
	
	/// Source cache for reloading
	char* mSource;
	/// Size of source
	uint mSourceSize;
	/// Flag to check if the shader has been compiled
	bool mIsCompiled;

public:
	Shader(ShaderType type);
	virtual ~Shader(void);

	// ::IShader
	ShaderType getType(void) const { return mType; }

	bool isCompiled(void) const { return mIsCompiled; }
	void compileWithSource(const char* src);
	void compileWithSource(const char* src, size_t length);

private:
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \brief	Implementation of the compilation process.
	////////////////////////////////////////////////////////////////////////////////////////////////////
	virtual void compileImpl(void) = 0;
};


////////////////////////////////////////////////////////////////////////////////////////////////////
/// \brief	Shader program.
////////////////////////////////////////////////////////////////////////////////////////////////////
class B2D_API ShaderProgram
	: public IShaderProgram
{
	B2D_OBJECT

protected:
	enum { ShaderTypeCount = 2 };

	/// Shaders, only one shader per type is allowed
	Shader* mShaders[ShaderTypeCount];

	/// Flag to mark if a new shader program has been added or removed and thus
	/// needed relinking to work as intended
	bool mNeedsRelinking;
	/// Flag to mark if the shader program has been linked (not neccesarily up to date)
	bool mLinked;

public:
	ShaderProgram(void);
	virtual ~ShaderProgram(void);


	// ::IShaderProgram
	Shader* operator[] (ShaderType type) const;

	bool isLinked(void) const { return mLinked; }
	bool needsRelinking(void) const { return mNeedsRelinking; }
	void link(void);

	Shader* addShader(ShaderType type);
	void removeShader(ShaderType type);
	Shader* getShader(ShaderType type) const;
	


private:
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \brief	Implementation of linking.
	////////////////////////////////////////////////////////////////////////////////////////////////////
	virtual void linkImpl(void) = 0;
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \brief	Implementation of adding a shader, needs to create the shader and attach it.
	/// 		Needs to be implemented by API specific implementation.
	///
	/// \param	type	The type of shader.
	///
	/// \return	The new shader.
	////////////////////////////////////////////////////////////////////////////////////////////////////
	virtual Shader* addShaderImpl(ShaderType type) = 0;
	////////////////////////////////////////////////////////////////////////////////////////////////////
	/// \brief	Implementation of removing a shader, just needs to detach it.
	/// 		Needs to be implemented by API specific implementation.
	///
	/// \param [in]	shader	Shader to remove.
	////////////////////////////////////////////////////////////////////////////////////////////////////
	virtual void removeShaderImpl(Shader* shader) = 0;
};

NS_B2D_END

#endif